#include "wthread.h"
#include <process.h>

namespace log4x
{
static DWORD key = 0;

typedef void* (*routine)(void* , int);
typedef struct
{
    routine    entry;
    int        id;
    void     * data;
} arg_s;

static unsigned
__stdcall address(void* data)
{
    arg_s *arg = (arg_s *)data;

    arg->entry(arg->data, arg->id);

    if (0 != key)
    {
        void*  ptr = TlsGetValue(key);

        if (ptr)
        {
            LocalFree(ptr);
        }
    }

    delete arg;

    return 0;
}

void
wthread::sleep(long ms)
{
    Sleep(ms);
}

THREAD
wthread::start(void* (* entry)(void* , int), void* data, int id)
{
    unsigned int threadID;

    arg_s *arg = new arg_s();
    arg->entry = entry;
    arg->id    = id;
    arg->data  = data;

    THREAD t = (THREAD)_beginthreadex(NULL, 0, address, arg, 0, &threadID);
    if (!t)
    {
        return 0;
    }

    return t;
}

void
wthread::end(THREAD &t, int timeout)
{
    if (t)
    {
        unsigned int to = INFINITE;

        (0 == timeout) ? to = INFINITE : to = timeout;

        switch (WaitForSingleObject((void* )t, to))
        {
        case WAIT_TIMEOUT:
            break;
        }

        ::CloseHandle(t);
        t = NULL;
    }
}

void
wthread::detach(THREAD &t)
{
    if (t)
    {
        ::CloseHandle(t);
        t = NULL;
    }
}

long
wthread::tid()
{
    return (long)GetCurrentThreadId();
}

void*
wthread::get_tls()
{
    if (0 == key)
    {
        key = TlsAlloc();
    }

    return (void* )TlsGetValue(key);
}

void
wthread::set_tls(void* val)
{
    if (0 == key)
    {
        key = TlsAlloc();
    }

    TlsSetValue(key, val);
}

void
wthread::init_mutex(MUTEX &mtx)
{
    InitializeCriticalSection(&mtx);
}

void
wthread::uninit_mutex(MUTEX &mtx)
{
    DeleteCriticalSection(&mtx);
}

void
wthread::lock(MUTEX &mtx)
{
    EnterCriticalSection(&mtx);
}

void
wthread::unlock(MUTEX &mtx)
{
    LeaveCriticalSection(&mtx);
}
}
